package com.aloda.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.aloda.constant.EmpConstant;
import com.aloda.constant.ExceptionConstant;
import com.aloda.constant.JwtClaimsConstant;
import com.aloda.context.AdminBaseContext;
import com.aloda.dto.emp.*;
import com.aloda.entity.Emp;
import com.aloda.exception.BaseException;
import com.aloda.mapper.EmpMapper;
import com.aloda.properties.EmpProperties;
import com.aloda.properties.JwtProperties;
import com.aloda.properties.SaltProperties;
import com.aloda.query.EmpPageDTO;
import com.aloda.result.PageResult;
import com.aloda.service.EmpService;
import com.aloda.utils.CheckUtils;
import com.aloda.utils.JwtUtil;
import com.aloda.vo.emp.EmpExportVO;
import com.aloda.vo.emp.EmpLoginVO;
import com.aloda.vo.emp.EmpPageVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author aloda
 * @description 针对表【emp(管理员表)】的数据库操作Service实现
 * @createDate 2024-12-15 10:45:11
 */
@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements EmpService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private EmpMapper empMapper;

    @Resource
    private SaltProperties saltProperties;

    @Resource
    private JwtProperties jwtProperties;

    @Resource
    private EmpProperties empProperties;

    /**
     * 通过账号密码登录
     *
     * @param empLoginDTO
     * @return
     */
    @Override
    public EmpLoginVO loginByUnAndPw(EmpLoginDTO empLoginDTO) {
        // 接收账号密码
        String empAccount = empLoginDTO.getUsername();
        String empPassword = empLoginDTO.getPassword();
        // 校验账号密码格式
        if (!CheckUtils.checkAccount(empAccount)) {
            throw new BaseException(ExceptionConstant.ACCOUNT_ERROR);
        }
        if (!CheckUtils.checkPassword(empPassword)) {
            throw new BaseException(ExceptionConstant.PASSWORD_ERROR);
        }
        // 校验验证码
        VerifyServiceImpl.checkVerify(empLoginDTO.getCode(), empLoginDTO.getKey(), stringRedisTemplate);
        // 查询账号密码是否正确
        LambdaQueryWrapper<Emp> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        String transPassword = DigestUtils.md5DigestAsHex((empPassword + saltProperties.getPasswordSalt()).getBytes());
        lambdaQueryWrapper.eq(Emp::getEmpAccount, empAccount).eq(Emp::getEmpPassword, transPassword);
        Emp emp = empMapper.selectOne(lambdaQueryWrapper);
        // 不正确返回错误信息
        if (BeanUtil.isEmpty(emp)) {
            throw new BaseException(ExceptionConstant.LOGIN_FAIL);
        }
        // 校验账号状态
        if (emp.getEmpStatus() == EmpConstant.ACCOUNT_BANNED) {
            throw new BaseException(ExceptionConstant.ACCOUNT_BANNED_CODE, ExceptionConstant.ACCOUNT_BANNED);
        }
        // 登录成功后，生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.EMP_ID, emp.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getAdminSecretKey(),
                jwtProperties.getAdminTtl(),
                claims);
        // 返回用户登录VO
        return EmpLoginVO.builder()
                .id(emp.getId())
                .avatar(emp.getAvatar())
                .username(emp.getEmpAccount())
                .auth(emp.getAuth())
                .token(token)
                .build();
    }

    /**
     * 分页查询
     *
     * @param empPageDTO
     * @return
     */
    @Override
    public PageResult<EmpPageVO> pageQuery(EmpPageDTO empPageDTO) {
        // 开启分页
        Page<Emp> page = empPageDTO.toMpPageDefaultSortByUpdateTimeDesc();
        // 构建条件
        LambdaQueryWrapper<Emp> empLambdaQueryWrapper = new LambdaQueryWrapper<>();
        empLambdaQueryWrapper.like(empPageDTO.getEmpAccount() != null, Emp::getEmpAccount, empPageDTO.getEmpAccount())
                .like(empPageDTO.getEmpName() != null, Emp::getEmpName, empPageDTO.getEmpName())
                .between(empPageDTO.getBeginTime() != null && empPageDTO.getEndTime() != null,
                        Emp::getCreateTime, empPageDTO.getBeginTime(), empPageDTO.getEndTime());
        // 查询分页
        Page<Emp> empPage = empMapper.selectPage(page, empLambdaQueryWrapper);
        // 数据处理
        return PageResult.of(empPage, EmpPageVO.class);
    }

    /**
     * 新增员工
     *
     * @param empAddDTO
     */
    @Override
    public Integer addEmp(EmpAddDTO empAddDTO) {
        // 格式校验
        if (!CheckUtils.checkAccount(empAddDTO.getEmpAccount())) {
            throw new BaseException(ExceptionConstant.ACCOUNT_ERROR);
        }
        if (!CheckUtils.checkEmail(empAddDTO.getEmail())) {
            throw new BaseException(ExceptionConstant.EMAIL_ERROR);
        }
        // 判断账号是否已存在
        Emp result = empMapper.selectEmpByAccount(empAddDTO.getEmpAccount());
        if (result != null) {
            throw new BaseException(ExceptionConstant.ACCOUNT_NOT_UNIQUE);
        }
        // 创建员工
        Emp emp = BeanUtil.copyProperties(empAddDTO, Emp.class);
        // 添加其他字段
        emp.setAuth(EmpConstant.EMP);
        emp.setEmpStatus(EmpConstant.ACCOUNT_NORMAL);
        Emp createUser = empMapper.selectById(AdminBaseContext.getCurrentId());
        emp.setCreateUser(createUser.getEmpName());
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateUser(createUser.getEmpName());
        emp.setUpdateTime(LocalDateTime.now());
        // 添加默认密码
        String transPassword = DigestUtils.md5DigestAsHex((empProperties.getEmpPassword() + saltProperties.getPasswordSalt()).getBytes());
        emp.setEmpPassword(transPassword);
        // 新增员工
        return empMapper.insert(emp);
    }

    /**
     * 编辑员工
     *
     * @param empEditDTO
     * @return
     */
    @Override
    public Integer editEmp(EmpEditDTO empEditDTO) {
        if (!CheckUtils.checkEmail(empEditDTO.getEmail())) {
            throw new BaseException(ExceptionConstant.EMAIL_ERROR);
        }
        Emp emp = BeanUtil.copyProperties(empEditDTO, Emp.class);
        Emp updateUser = empMapper.selectById(AdminBaseContext.getCurrentId());
        emp.setUpdateUser(updateUser.getEmpName());
        emp.setUpdateTime(LocalDateTime.now());
        return empMapper.updateById(emp);
    }

    /**
     * 重置密码
     *
     * @param id
     */
    @Override
    public void resetPassword(Long id) {
        Emp emp = empMapper.selectById(id);
        String pw = DigestUtils.md5DigestAsHex((empProperties.getEmpPassword() + saltProperties.getPasswordSalt()).getBytes());
        emp.setEmpPassword(pw);
        empMapper.updateById(emp);
    }

    /**
     * 员工编辑个人信息
     *
     * @param empInfoDTO
     */
    @Override
    public void empEditInfo(EmpInfoDTO empInfoDTO) {
        if (!CheckUtils.checkPhone(empInfoDTO.getPhone())) {
            throw new BaseException(ExceptionConstant.PHONE_ERROR);
        }
        if (!CheckUtils.checkEmail(empInfoDTO.getEmail())) {
            throw new BaseException(ExceptionConstant.EMAIL_ERROR);
        }
        Emp emp = BeanUtil.copyProperties(empInfoDTO, Emp.class);
        Long currentId = AdminBaseContext.getCurrentId();
        emp.setId(currentId);
        emp.setUpdateUser(empInfoDTO.getEmpName());
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.updateById(emp);
    }

    /**
     * 员工修改个人密码
     *
     * @param empEditPwDTO
     */
    @Override
    public void empEditPassword(EmpEditPwDTO empEditPwDTO) {
        if (!CheckUtils.checkPassword(empEditPwDTO.getOldPassword())
                || !CheckUtils.checkPassword(empEditPwDTO.getNewPassword())) {
            throw new BaseException(ExceptionConstant.PASSWORD_ERROR);
        }
        Long currentId = AdminBaseContext.getCurrentId();
        Emp emp = empMapper.selectById(currentId);
        String oldPassword = DigestUtils.md5DigestAsHex((empEditPwDTO.getOldPassword() + saltProperties.getPasswordSalt()).getBytes());
        if (!emp.getEmpPassword().equals(oldPassword)) {
            throw new BaseException(ExceptionConstant.OLD_PASSWORD_ERROR);
        }
        String newPassword = DigestUtils.md5DigestAsHex((empEditPwDTO.getNewPassword() + saltProperties.getPasswordSalt()).getBytes());
        emp.setEmpPassword(newPassword);
        empMapper.updateById(emp);
    }

    /**
     * 导出员工信息到Excel
     *
     * @param response HttpServletResponse
     */
    @Override
    public void exportEmpToExcel(HttpServletResponse response, List<Long> ids) {
        try {
            // 设置响应头
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("员工信息表", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            // 查询所有员工信息 如果ids为空查询所有信息，否则查询对应信息
            LambdaQueryWrapper<Emp> queryWrapper = new LambdaQueryWrapper<>();
            List<Emp> empList;
            if (ids.isEmpty()) {
                empList = empMapper.selectList(queryWrapper);
            } else {
                empList = empMapper.selectBatchIds(ids);
            }

            // 转换为导出VO
            List<EmpExportVO> exportVOList = empList.stream().map(emp -> BeanUtil.copyProperties(emp, EmpExportVO.class))
                    .collect(Collectors.toList());

            // 使用EasyExcel导出
            EasyExcel.write(response.getOutputStream(), EmpExportVO.class)
                    .sheet("员工信息")
                    .doWrite(exportVOList);

        } catch (IOException e) {
            throw new RuntimeException(ExceptionConstant.EXPORT_EXCEL_ERROR, e);
        }
    }
}




